﻿Imports iConverter.Models
Imports System.Text
Imports System.IO
Imports System.Runtime.CompilerServices



Namespace Core



    ''' <summary>
    ''' 提供用于创建转换文档的工厂方法
    ''' </summary>
    ''' <remarks></remarks>
    Public Module ConvertDocumentFactory



#Region "对已有文档的操作"

        ''' <summary>
        ''' 使用文档源编码重新加载文件
        ''' </summary>
        ''' <exception cref="ArgumentNullException">当 doc 参数 为空的时候引发</exception>
        ''' <exception cref="InvalidOperationException">当文档不是从文件加载进来的时候引发</exception>
        ''' <remarks>仅限从文件加载的文档才可以操作</remarks>
        Public Sub ReOpen(ByVal doc As ConvertDocument)
            If doc Is Nothing Then
                Throw New ArgumentNullException("Doc")
            End If

            If String.IsNullOrEmpty(doc.FileName) OrElse Not File.Exists(doc.FileName) OrElse doc.SourceEncoding Is Nothing Then
                Throw New InvalidOperationException()
            End If

            'Dim fi As New FileInfo(doc.FileName)

            Dim str = My.Computer.FileSystem.ReadAllText(doc.FileName, doc.SourceEncoding)

            doc.Content = str


        End Sub

#End Region




#Region "创建新的实例"

        ''' <summary>
        ''' 创建新的文档实例
        ''' </summary>
        ''' <returns></returns>
        ''' <remarks>使用默认配置创建</remarks>
        Public Function CreateNew() As ConvertDocument

            Dim doc As New ConvertDocument With
                {.Name = "Untitled", .ContentEncoding = EncodingManager.DefaultEncoding, .SourceEncoding = EncodingManager.DefaultEncoding, .DestinationEncoding = EncodingManager.UTF8}
            '内容编码，源编码有待修正

            Return doc
        End Function


        ''' <summary>
        ''' 从文件初始化新的文档对象
        ''' </summary>
        ''' <param name="filename">文件名</param>
        ''' <exception cref="ArgumentNullException">当 参数 为空（nothing） 或空白的时候引发</exception>
        ''' <exception cref="ArgumentException">当 filename 所指定的文件不存在的时候引发</exception>
        ''' <remarks></remarks>
        Public Function CreateFromFile(ByVal filename As String) As ConvertDocument
            If String.IsNullOrEmpty(filename) OrElse String.IsNullOrWhiteSpace(filename) Then
                Throw New ArgumentNullException("filename")
            End If

            If Not File.Exists(filename) Then
                Throw New ArgumentException("File isnot Exites", "filename")
            End If

            Dim fi As New FileInfo(filename)

            Dim encode = DetectFileEncoding(fi.FullName)
            Dim filestr = My.Computer.FileSystem.ReadAllText(fi.FullName, encode)


            Dim doc As New ConvertDocument(fi.FullName, filestr) With
                              {.Name = fi.Name,
                               .ContentEncoding = encode,
                               .SourceEncoding = encode,
                               .DestinationEncoding = EncodingManager.UTF8}


            Return doc
        End Function




#End Region


#Region "其他方法"

        ''' <summary>
        ''' 编码器列表
        ''' </summary>
        ''' <remarks></remarks>
        Private _Encodingdict As Dictionary(Of Encoding, Byte())
        ''' <summary>
        ''' 创建编码器字典
        ''' </summary>
        ''' <remarks></remarks>
        Private Sub CreateDetectEncodingDict()
      

            '_Encodingdict = (From item In EncodingManager.UnicodeEncodingList
            '                Select item, BOM = item.GetPreamble()).ToDictionary(Function(x) (x.item), Function(y) (y.BOM))

            _Encodingdict = New Dictionary(Of Encoding, Byte())
            For Each item In EncodingManager.UnicodeEncodingList
                _Encodingdict.Add(item, item.GetPreamble)
            Next


        End Sub
        ''' <summary>
        ''' 检测文件编码
        ''' </summary>
        ''' <param name="filename">文件名</param>
        ''' <exception cref="ArgumentNullException">当 参数 为空（nothing） 或空白的时候引发</exception>
        ''' <exception cref="ArgumentException">当 filename 所指定的文件不存在的时候引发</exception>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Private Function DetectFileEncoding(ByVal filename As String) As Encoding

            If String.IsNullOrEmpty(filename) OrElse String.IsNullOrWhiteSpace(filename) Then
                Throw New ArgumentNullException("filename")
            End If

            If Not File.Exists(filename) Then
                Throw New ArgumentException("File isnot Exites", "filename")
            End If


            If _Encodingdict Is Nothing Then CreateDetectEncodingDict()


            Dim maxBOMlen = _Encodingdict.Values.Max(Function(x) (x.Length))

            Dim fi As New FileInfo(filename)

            Dim readbytesCount As Integer ' = If(maxBOMlen <= fi.Length, maxBOMlen, fi.Length)
            Dim BomBytes(maxBOMlen) As Byte ' = Nothing

            Using fs = fi.OpenRead
                ' Dim buff(maxBOMlen) As Byte
                readbytesCount = fs.Read(BomBytes, 0, maxBOMlen)
                '  BomBytes = buff.Take(readbytesCount).ToArray()

            End Using




            For Each item In _Encodingdict

                If item.Value.StartsWith(BomBytes) Then
                    Return item.Key
                End If

            Next


            Return Encoding.Default
        End Function
#End Region


#Region "扩展方法"





        ''' <summary>
        ''' 确定字节数组x的开头是否与指定的字节数组y匹配。
        ''' </summary>
        ''' <param name="x">要比较的字节数组</param>
        ''' <param name="y">要比较的字节数组</param>
        ''' <returns></returns>
        ''' <remarks>扩展方法</remarks>
        <Extension()>
        Public Function StartsWith(ByVal x As Byte(), ByVal y As Byte()) As Boolean

            If x IsNot Nothing AndAlso
               y IsNot Nothing Then

                '2011-04-09 03-35 修订，（工作项:20455）解决索引溢出
                Dim count As Integer = Math.Min(x.Length, y.Length) - 1

                For i = 0 To count
                    If x(i) <> y(i) Then Return False
                Next
                Return True
            End If

            Return False
        End Function


        ''' <summary>
        ''' 确定文档是否是从文件加载
        ''' </summary>
        ''' <param name="doc">要检测的文档</param>
        ''' <returns></returns>
        ''' <remarks>扩展方法</remarks>
        <Extension()>
        Public Function IsFromFile(ByVal doc As ConvertDocument) As Boolean
            If Not String.IsNullOrEmpty(doc.FileName) AndAlso
                File.Exists(doc.FileName) Then
                Return True
            End If

            Return False
        End Function


#End Region



    End Module


End Namespace

